あたらしいテストフレームワークVitestをReactで試してみた
はじめに
こんにちは、CX事業本部MAD事業部の森茂です。
今回まだ開発版ではありますが、昨年末に公開されたVue.jsやViteの作者Anthony Fu氏@antfu7、Patak氏@patak_devが開発しているJestに代わるあたらしい高速テストフレームワークVitestをReactで試してみました。
VitestはVite環境で動作する高速なテストフレームワークで、VueやReact、Svelte、litなどなどさまざまなフレームワークで動作します。ChaiやJestのアサーション、スナップショットが互換的に動作するので既存のテストコードをほぼ同じ書き方で利用することができます。またc8を利用したcoverageの作成にも対応しています。
Jestでは環境の構築にそれなりの手間がかかりますが、Vitestはライブラリのインストールと簡単な設定を追記するだけで利用することが可能です。
なお、Vitestはまだ開発中のテストフレームワークのためプロダクションでの利用は推奨されていませんのでその点ご了承ください。
Vite環境の構築
今回はcreate vite
を利用してReact + TypeScriptの環境を用意します。
$ yarn create vite vitest-react-sample --template react-ts $ cd vitest-react-sample
create vite
直後は下記のディレクトリ構成となります。
├── index.html ├── package.json ├── src │ ├── App.css │ ├── App.tsx │ ├── favicon.svg │ ├── index.css │ ├── logo.svg │ ├── main.tsx │ └── vite-env.d.ts ├── tsconfig.json ├── vite.config.ts └── yarn.lock
この状態で一度起動の確認をしておきます。
$ yarn dev
今回は初期時に用意されているこの画面に対してVitestで簡単なテストコードを用意していきます。
Vitestのセットアップ
Vitestをインストールします。(執筆時の最新版はv0.1.20)
$ yarn add -D vitest
React TestingライブラリなどReactのテストに必要な各種ライブラリをインストールします。また今回DOMのレンダリングに利用するのはjs-dom
ではなくjs-dom互換でSSRにも対応、パフォーマンスも倍以上速いと謳っているhappy-domを利用してみました。
$ yarn add -D @testing-library/react $ yarn add -D @testing-library/jest-dom $ yarn add -D happy-dom $ yarn add -D @testing-library/user-event @types/testing-library__user-event $ yarn add -D jest-extended
Vitest用の設定をvite.config.ts
ファイルに追記します。設定を一部追記するだけでテスト環境が用意できるのは楽ですね。
/// <reference types="vitest" /> import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' // https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], test: { global: true, environment: 'happy-dom', setupFiles: './src/setup.ts', }, })
test実行用のセットアップファイルを用意します。jest用の拡張されたアサーションも利用できるようにimportしておきます。もちろん利用する必要がない場合は不要です。
import '@testing-library/jest-dom/extend-expect' import 'jest-extended';
App.test.tsx
ファイルとしてテストコードを用意します。スナップショットとレンダリング結果に対してのテキスト要素のチェックを行う単純なテストコードです(extend-expect
、jest-extended
のアサーションを使うために少々無理やり感ありです)。describe
やtest
などJestとは異なりグローバルでは展開されないため、それぞれをimportする必要がありますが、記載方法はほぼ同じにとなっているので既存のテストコードからの移行もしやすいと思います。
import '@testing-library/jest-dom' // jestのアサーションがエラーになる場合は明示的にimport import { describe, expect, test } from 'vitest' import App from './App' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' describe('Simple working test', () => { test('should render correctly', () => { const {container} = render(<App />) expect(container.firstChild).toMatchSnapshot() }) // extend-expectのmatcher[toBeInTheDocument] test('the title is visible', () => { render(<App />) expect(screen.getByText(/Hello Vite \+ React!/i)).toBeInTheDocument() }) // jest-extendedのmatcher[toBeEmptyDOMElement] test('should increment count on click', async() => { render(<App />) userEvent.click(screen.getByRole('button')) expect(await screen.findByText(/count is: 1/i)).not.toBeEmptyDOMElement() }) })
なお、今回検証のために用意した環境ではJestの拡張されたアサーションの型情報がVitestにはまだ入っていないようでエディタ上ではTypeエラーが出ました。Vite環境ではtype-checkが走らないのでこのままでも動作はしますが、現時点では自分で型情報を用意するなど別途対応が必要そうです。(明示的にimportすることでもTypeエラーは消えるようですが何か設定が足りないだけなのかもしれません。。。)
テストの実行
環境の準備ができたところでさっそくテストを実行してみます。
$ yarn test
初回スナップショットの生成も合わせてこの1.15秒で完了です。
一部テストコードを書き換えて保存した際の再テストについては20msと一瞬で終わりました:)
coverageをとってもこの速度。
Jestとの比較
参考までに同じプロジェクトにJest(ts-jest)を導入して何度が計測してみたところ結果は下記のようになりました。
テスト内容 | Vitest | Jest |
---|---|---|
App.test.tsx | 1.15s | 3.77s |
watch | 20ms | 3.181s |
coverage | 1.77s | 6.024s |
単純なテストですがそれでも各項目で想像以上に速度の差があることがわかりました。
開発環境
- MacBook Pro (13-inch, M1, 2020)
- macOS Monterey
- node v16.13.1
- vite v2.7.2
- vitest v0.1.20
- jest 27.4.7
- ts-jest 27.1.3
- happy-dom 2.27.0
さいごに
まだ開発中ながら一度この速度感に慣れてしまうとJestには戻れなくなってしまいそうです。。Jest互換の記載で書きすすめることができ、移行も容易そうなので正式リリース後にはテストフレームワークとして有力な選択肢となりそうです。Vitest今後の開発が楽しみですね。